function bpr = binary_pianoroll(nmat, nfrms, varargin)
% function bpr = binary_pianoroll(nmat, nfrms, varargin)
%
% Creates binary pianoroll matrices for a given note matrix.
%
% Input:
%   nmat     [mat]  - The note matrix to process.
%   nfrms    [num]  - The number of desired frames in the pianoroll.
%  OPTIONAL (passed in name-value pairs):
%   pitches  [vec]  - The minimum and maximum MIDI pitch numbers that define
%                     the range of the pianoroll (number of columns).  This
%                     can also be a vector of pitches, although only the
%                     first and last values will be considered.  If empty,
%                     then we use nmat to define the range. [20 100]
%   duration [num]  - Duration to use when calculating length of pianoroll.
%                     If empty, this is calculated from nmat. [[]]
%   sep_chan [bool] - If true, we consider each channel in the nmat
%                     separately, otherwise all activity is combined into 
%                     one matrix. [true]
%
% Output:
%   bpr      [cell] - Binary pianorolls contained in a cell array.
%

% Copyright (C) 2010-2030 Graham Grindlay (grindlay@ee.columbia.edu)
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.

% process args
[pitches, duration, sep_chan] = parse_opt(varargin, 'pitches', [20 100], ...
                                                    'duration', [], ...
                                                    'sep_chan', 1);

if isempty(pitches)
    pitches = [min(pitch(nmat)) max(pitch(nmat))];
else
    pitches = [pitches(1) pitches(end)];
end

if isempty(duration)
    mdur = nmat_dur(nmat);
else
    mdur = duration;
end

chs = mchannels(nmat);

S = length(chs);
P = diff(pitches)+1;

flen = mdur/nfrms;

nmats = cell(1,S);
bpr = cell(1,S);
for s = 1:S
    bpr{s} = sparse(zeros(P,nfrms));
    nmats{s} = nmat(channel(nmat)==chs(s),:);
  
    % find frame indices for the onsets of this source
    ot = 1+floor(onset(nmats{s}, 'sec')/flen);
    
    % find number of frames for the durations of this source
    dt = round(dur(nmats{s}, 'sec')/flen);
    
    pt = pitch(nmats{s})-pitches(1)+1;
    
    % 'fill in' the pitch-frame bins between onset and offset of each note
    for i = 1:length(ot)
        bpr{s}(pt(i),ot(i):(ot(i)+dt(i)-1)) = 1;
    end
    bpr{s} = bpr{s}(:,1:nfrms);
end

% combine results if asked
if ~sep_chan && S>1
    bpr = or(bpr{:});
end

% if only 1 source, don't return cell array
if S==1
    bpr = bpr{1};
end

